﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace AMDev.BNET.ClientAPI
{
    public abstract class BNETBaseClient
        : ClientObservableObject 
    {
        #region Fields

        protected HttpClient httpClient = null;        
        private RegionsEnumeration region;

        #endregion

        #region Properties

        public RegionsEnumeration Region
        {
            get
            {
                return this.region;
            }
            set
            {
                this.SetProperty(ref this.region, value);
            }
        }

        #endregion

        #region .ctor

        public BNETBaseClient()
            : this(RegionsEnumeration.US)
        {         
        }

        public BNETBaseClient(RegionsEnumeration region)
        {
            this.httpClient = new HttpClient();
            this.Region = region;
        }

        #endregion

        #region Methods

        #region Helpers 

        protected String BuildServiceUri(String function)
        {
            return this.BuildServiceUri(null, function);
        }

        protected String BuildServiceUri(String context, String function)
        {
            StringBuilder functionUriBuilder = null;
            
            if (String.IsNullOrWhiteSpace(function))
                throw new ArgumentNullException("function");

            functionUriBuilder = new StringBuilder();
            functionUriBuilder.Append("http://");
            functionUriBuilder.Append(this.region.GetHost());

            if (!String.IsNullOrWhiteSpace(context))
                functionUriBuilder.Append(context);

            // If the used GetRestAPIFunctionFromMethod, the context is built-in inside the method attribute.
            functionUriBuilder.Append(function);

#if DEBUG
            Debug.WriteLine("API REST function url: " + functionUriBuilder.ToString() + Environment.NewLine);
#endif
            return functionUriBuilder.ToString();
        }

        protected String GetRestAPIFunctionFromMethod([CallerMemberName] String methodName = null, Type clientType = null)
        {
            BNETApiMethodAttribute[] methodAttributes = null;
            BNETApiMethodAttribute selectedAttribute = null;
            String restFunction = null;
            MethodInfo methodInfo = null;

            if (String.IsNullOrWhiteSpace(methodName))
                throw new ArgumentNullException("methodName");

            if (clientType == null)
                clientType = this.GetType();

            methodInfo = clientType.GetMethod(methodName);
            methodAttributes = methodInfo.GetCustomAttributes(typeof(BNETApiMethodAttribute), true) as BNETApiMethodAttribute[];
            if (methodAttributes != null)
            {
                selectedAttribute = methodAttributes.FirstOrDefault();
                if (selectedAttribute != null)
                    restFunction = selectedAttribute.ToString();
            }

            return restFunction;
        }

        #endregion

        #region Async Methods

        protected async Task<String> GetRestDataAsync(String requestUri)
        {
            String restData = null;
            Task<String> requestTask = null;

            if (String.IsNullOrWhiteSpace(requestUri))
                throw new ArgumentNullException("url");

            if (this.httpClient == null)
                throw new NullReferenceException("httpClient");

            try
            {

                requestTask = this.httpClient.GetStringAsync(requestUri);
                restData = await requestTask;

                try
                {
                    if (requestTask.IsFaulted == true)
                        restData = String.Empty;
                }
                catch (Exception)
                {
                }
            }
            catch (Exception exc)
            {
                Debug.WriteLine(exc.ToString());
                restData = String.Empty;
            }

            return restData;
        }

        #endregion

        #endregion
    }
}
